﻿// -----------------------------------------------------------------------
// <copyright file="GenericRepository.cs" company="AGR">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace AGR.Data.Repository.Contract
{
    using System;
    using System.Linq;
    using System.Data.Linq;
    using System.Linq.Expressions;
    using System.Collections.ObjectModel;
    using AGR.Data.Context;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        private AGRContext _context;
        private Table<TEntity> _entity;

        #region Constuctor
        public GenericRepository()
        {
            _context = new AGRContext();
            _entity = _context.GetTable<TEntity>();
        }
        #endregion

        #region Destuctor
        ~GenericRepository()
        {
            Dispose(false);
        }
        #endregion

        #region Methods

        public TEntity FindByCode(string code)
        {
            if (string.IsNullOrEmpty(code))
                throw new ArgumentNullException();

            throw new NotImplementedException();
        }

        public IQueryable<TEntity> FindBy(Expression<Func<TEntity, bool>> predicate)
        {
            if (predicate == null)
                throw new ArgumentNullException();

            return _entity.Where(predicate);
        }

        public ReadOnlyCollection<TEntity> FindByReadOnly(Expression<Func<TEntity, bool>> predicate)
        {
            if (predicate == null)
                throw new ArgumentNullException();

            return _entity.Where(predicate).ToList().AsReadOnly();
        }

        public TEntity FindSingleBy(Expression<Func<TEntity, bool>> predicate)
        {
            if (predicate == null)
                throw new ArgumentNullException();

            return _entity.Where(predicate).SingleOrDefault();
        }

        public IQueryable<TEntity> FindOrderBy(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
        {
            IQueryable<TEntity> query = _entity;

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                //query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query);
            }
            else
            {
                return query;
            }
        }

        public ReadOnlyCollection<TEntity> FindOrderByReadOnly(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
        {
            IQueryable<TEntity> query = _entity;

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                //query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList().AsReadOnly();
            }
            else
            {
                return query.ToList().AsReadOnly();
            }
        }

        public IQueryable<TEntity> GetAll()
        {
            return _entity;
        }

        public ReadOnlyCollection<TEntity> GetAllReadOnly()
        {
            return _entity.ToList().AsReadOnly();
        }

        public void Add(TEntity entity)
        {
            if (entity == null)
                throw new ArgumentNullException();

            _entity.InsertOnSubmit(entity);
        }

        public void Update(TEntity entity)
        {
            if (entity == null)
                throw new ArgumentNullException();

            throw new NotImplementedException();
        }

        public void Delete(TEntity entityToDelete)
        {
            if (entityToDelete == null)
                throw new ArgumentNullException();

            _entity.DeleteOnSubmit(entityToDelete);
        }

        public void DeleteBy(Expression<Func<TEntity, bool>> predicate)
        {
            if (predicate == null)
                throw new ArgumentNullException();

            IQueryable<TEntity> entitiesToDelete = _entity.Where(predicate);

            foreach (TEntity entity in entitiesToDelete)
            {
                Delete(entity);
            }
        }

        public void DeleteByCode(string code)
        {
            if (string.IsNullOrEmpty(code))
                throw new ArgumentNullException();

            throw new NotImplementedException();
        }

        public void SaveChanges()
        {
            _context.SubmitChanges();
        }

        #endregion

        #region Dispose

        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}